home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / text / print / post_src_186enh.lha / post.c < prev    next >
C/C++ Source or Header  |  1993-02-07  |  69KB  |  2,309 lines

  1. /* PostScript interpreter file "post.c" - the main program (Amiga)
  2.  * (C) Adrian Aylward 1989, 1992
  3.  *
  4.  * This file contains the code to parse the command line arguments, the
  5.  * WorkBench and intuition interface, and the printer screen or IFF file]
  6.  * output routines.  It is therfore heavily Amiga dependent.  It calls the
  7.  * interpreter library for all the PostScript stuff.
  8.  *
  9.  * There are also various Lattice dependencies: the startup code in _main,
  10.  * the menu task, the flush and copy functions, and the floating point trap
  11.  * and break handling.
  12.  *
  13.  * V1.6 First full source release
  14.  * V1.7 Treat "*" as interactive
  15.  * V1.8 Major revamping of interface, removal of 1.3 compatibility
  16.  *      revisions programmed by Robert Poole
  17.  * V1.85 Added an option to enable compatibility with so-called "sunmouse"
  18.  *       and "autopoint" commodities.
  19.  * V1.86 Fixed a little bug that appears to be my fault.
  20.  */
  21.  
  22. #include <dos.h>
  23. #include <devices/printer.h>
  24. #include <devices/prtbase.h>
  25. #include <exec/exec.h>
  26. #include <exec/execbase.h>
  27. #include <exec/tasks.h>
  28. #include <graphics/displayinfo.h>
  29. #include <graphics/gfxbase.h>
  30. #include <graphics/text.h>
  31. #include <intuition/intuition.h>
  32. #include <intuition/gadgetclass.h>
  33. #include <libraries/dosextens.h>
  34. #include <libraries/asl.h>
  35. #include <libraries/gadtools.h>
  36. #include <workbench/icon.h>
  37. #include <workbench/startup.h>
  38. #include <workbench/workbench.h>
  39. #include <proto/diskfont.h>
  40. #include <proto/dos.h>
  41. #include <proto/exec.h>
  42. #include <proto/graphics.h>
  43. #include <proto/icon.h>
  44. #include <proto/intuition.h>
  45. #include <clib/asl_protos.h>
  46. #include <clib/gadtools_protos.h>
  47. #include <stdlib.h>
  48. #include <stdio.h>
  49. #include <string.h>
  50. #include <ctype.h>
  51.  
  52. #include "postlib.h"
  53. #include "Post_interface.h"
  54.  
  55. /* prototype for my HACK */
  56. void TackOn(char *, char *, char *);
  57.  
  58. #undef  POSTVERNO
  59. #define POSTVERNO 15  /* We need post.library version 1.5+ */
  60.  
  61. /* Assembler routines */
  62.  
  63. extern void insertbreak(void);
  64. extern void deletebreak(void);
  65. extern void insertftrap(void);
  66. extern void deleteftrap(void);
  67.  
  68. /* Routines defined and referenced only within this module */
  69.  
  70. extern void errmsg(char *string);
  71. extern void tidyup(void);
  72. extern void setprinter(void);
  73. extern void setprintden(void);
  74. extern void setreqgadgets(void);
  75. extern void getreqgadgets(void);
  76. extern void enablegadg(struct Gadget *gadget, int enable);
  77. extern void setgadgcbox(struct Gadget *gadget, int value);
  78. extern int  getgadgcbox(struct Gadget *gadget);
  79. extern void setgadgint(struct Gadget *gadget, int value);
  80. extern int  getgadgint(struct Gadget *gadget);
  81. extern int  getgadgabs(struct Gadget *gadget);
  82. extern int  strtoint(char **sp, int *ip);
  83. extern void sendmenu(int action);
  84. extern void __saveds menuproc(void);
  85. # ifndef STATICLINK
  86. extern void __saveds __asm flushpage(register __d0 int y1,
  87.                                      register __d1 int y2);
  88. extern void __saveds __asm copypage(register __d0 int num);
  89. # endif
  90. extern void printpage(void);
  91. extern void iffpage(void);
  92. extern int  igcd(int n, int m);
  93. void __saveds sigfpe(void);
  94. void __saveds sigint(void);
  95.  
  96. /* Message structure */
  97.  
  98. struct PSmessage
  99. {   struct Message ExecMessage;
  100.     long class;            /* Always zero */
  101.     short action;          /* Action - from Post to handler */
  102.     short command;         /* Command - from handler to Post */
  103.     struct BitMap *bitmap; /* The bitmap */
  104.     short y1, y2;          /* Min and max+1 y values to flush */
  105.     short result;          /* Result  (return code) */
  106.     short length;          /* Length of string */
  107.     char *string;          /* String */
  108.     long window;           /* Always zero */
  109.     short errnum;          /* Last error number */
  110.     short zero;            /* Reserved, presently always zero */
  111. };
  112.  
  113. /* Actions */
  114.  
  115. #define PSACTOPEN    1 /* Open */
  116. #define PSACTCLOSE   2 /* Close */
  117. #define PSACTFLUSH   3 /* Flush out the bitmap */
  118. #define PSACTPAUSE   4 /* Pause at the end of a page */
  119. #define PSACTCOMMAND 5 /* Get a command */
  120. #define PSACTEXIT    6 /* Exit */
  121.  
  122. /* Commands */
  123.  
  124. #define PSCOMQUIT    1 /* Quit */
  125. #define PSCOMRESTART 2 /* Restart */
  126. #define PSCOMFILEF   3 /* Load Font */
  127. #define PSCOMFILEL   4 /* Load File */
  128. #define PSCOMFILER   5 /* Run File */
  129. #define PSCOMINTER   6 /* Interactive */
  130.  
  131. /* SAS startup */
  132.  
  133. extern struct ExecBase *SysBase;
  134. extern struct WBStartup *WBenchMsg;
  135.  
  136. /* External data (initialised to zero) */
  137.  
  138. int retcode, errcode, ioerror;
  139. int fatalerror, restarterror, requested;
  140.  
  141. int arec;
  142.  
  143. BPTR errfh, confh;
  144.  
  145. # ifndef STATICLINK
  146. struct library *PSbase;
  147. # endif
  148. struct PSparm parm;
  149. struct PSmessage menumsg;
  150.  
  151. struct Library *AslBase = NULL, *GadToolsBase = NULL;
  152. struct FileRequester *filereq, *filereq1, *filereq2;
  153.  
  154. struct Process *process;
  155. struct MsgPort *mainport, *menuport;
  156. struct Task *menutask;
  157. struct Screen *screen;
  158. struct Window *syswindow, *errwindow, *bitwindow, *intwindow;
  159. struct BitMap bitmap;
  160. struct ColorMap colormap;
  161. struct TextFont *textfont;
  162.  
  163. int propen, prden;
  164. struct IODRPReq prreq;
  165. struct PrinterData *prdata;
  166. struct PrinterExtendedData *prextdata;
  167. struct Preferences *prprefs;
  168. struct RastPort prrast;
  169. struct MsgPort *prport;
  170. ULONG prsig;
  171. UBYTE prstatus[2];
  172.  
  173. int breakset, ftrapset;
  174.  
  175. int winxbase, winybase, winxsize, winysize, winxpos, winypos;
  176.  
  177. /* Colour tables.  The default color map type is a vector or UWORD RGB
  178.  * values.  The colours are inverted as we set a bit in the bitmap whenever
  179.  * we want to place a drop of (black or cyan/magenta/yellow) ink */
  180.  
  181. static UWORD bcolors[16] =  /* Black and white */
  182. {   0xfff, 0x000, 0xf0f, 0x00f, /* White   black   magenta blue */
  183.     0xff0, 0x0f0, 0xf00, 0x000, /* Yellow  green   red     black */
  184.     0x000, 0x000, 0x000, 0x000, /* Black */
  185.     0xbbb, 0x888, 0x333, 0x000  /* lt-gray med-gray dk-gray Black */
  186. };
  187.  
  188. static UWORD ccolors[16] = /* Colour (RGB or CMYK) */
  189. {   0xfff, 0x0ff, 0xf0f, 0x00f, /* White   cyan    magenta blue */
  190.     0xff0, 0x0f0, 0xf00, 0x000, /* Yellow  green   red     black */
  191.     0x000, 0x000, 0x000, 0x000, /* Black */
  192.     0xbbb, 0x888, 0x333, 0x000  /* lt-gray med-gray dk-gray Black */
  193. };
  194.  
  195. char titlewait[]    = POSTVER " Copyright © 1989, 1992 Adrian Aylward";
  196. char titlestart[]   = POSTVER " Running startup file(s)";
  197. char titlerunning[] = POSTVER " Running";
  198. char titleinter[]   = POSTVER " Interactive";
  199. char titlepaused[]  = POSTVER " Paused";
  200.  
  201. char hailfilef[]    = POSTVER " Select font to load";
  202. char hailfilen[]    = POSTVER " Select file to load";
  203. char hailfiles[]    = POSTVER " Select file to run";
  204.  
  205. /* The default font and screen */
  206.  
  207. struct TextAttr topaz11 =       /* Font is Topaz 11 */
  208. {   "topaz.font", 11, FS_NORMAL, FPF_DISKFONT };
  209.  
  210. struct NewScreen newscreen =    /* Screen */
  211. {   0, 0, 640, 512, 1, 0, 15, LACE|HIRES, CUSTOMSCREEN, &topaz11,
  212.     (UBYTE *) &titlewait, NULL, NULL
  213. };
  214.  
  215. char undobuff[256];
  216.  
  217. /* Note: stuff for requester window has been moved into Post_interface.c
  218.    Rob Poole -- 2/3/93 */
  219.  
  220. /* Version string */
  221. char *version = "$VER: Post V1.86enh (7.2.93)";
  222.  
  223. struct NewWindow newerrwindow =
  224. {   0, 100, 640, 100, 0, 15,
  225.     0, SIMPLE_REFRESH | NOCAREREFRESH | WFLG_BACKDROP | WFLG_BORDERLESS,
  226.     NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, CUSTOMSCREEN
  227. };
  228.  
  229. /* Stuff for the windows */
  230.  
  231. struct PropInfo hscrollinfo =   /* Horizontal scroll proportional gadget */
  232. {   AUTOKNOB|FREEHORIZ, -1, -1, -1, -1 };
  233. struct Image hscrollimage;
  234. struct Gadget hscrollgadg =
  235. {   NULL, 0, -8, -14, 9,
  236.     GRELBOTTOM|GRELWIDTH, BOTTOMBORDER|RELVERIFY, PROPGADGET,
  237.     (APTR)&hscrollimage, NULL, NULL, 0, (APTR)&hscrollinfo, 0, NULL
  238. };
  239.  
  240. struct PropInfo vscrollinfo =   /* Vertical scroll proportional gadget */
  241. {   AUTOKNOB|FREEVERT, -1, -1, -1, -1 };
  242. struct Image vscrollimage;
  243. struct Gadget vscrollgadg =
  244. {   &hscrollgadg, -15, 0, 16, -8,
  245.     GRELRIGHT|GRELHEIGHT, RIGHTBORDER|RELVERIFY, PROPGADGET,
  246.     (APTR)&vscrollimage, NULL, NULL, 0, (APTR)&vscrollinfo, 0, NULL
  247. };
  248.  
  249. struct NewWindow newbitwindow = /* Bitmap window.  (Borders (4,2,18,10)) */
  250. {   0, 49, 640, 463, -1, -1,
  251.     0, SIMPLE_REFRESH,
  252.     &vscrollgadg, NULL, NULL, NULL, NULL,
  253.     0, 100, 0, 0, CUSTOMSCREEN
  254. };
  255.  
  256. struct NewWindow newintwindow = /* Interactive window */
  257. {   0, 12, 640, 37, -1, -1,
  258.     0, SIZEBRIGHT|WINDOWSIZING|SMART_REFRESH|ACTIVATE,
  259.     NULL, NULL, NULL, NULL, NULL,
  260.     0, 0, 0, 400, CUSTOMSCREEN
  261. };
  262.  
  263.  
  264. struct Menu *menu0, *menu1, *menu2;
  265.  
  266. /* GadTools menu, with 2.0 look -- R. Poole 2/1/93 */
  267.  
  268. struct NewMenu mainmenu[] = {
  269.   { NM_TITLE, "Project",          0, 0, 0, 0,},
  270.   { NM_ITEM,  "Restart",          0, 0, 0, 0,},
  271.   { NM_ITEM,  "Quit",           "Q", 0, 0, 0,},
  272.   { NM_TITLE, "File",             0, 0, 0, 0,},
  273.   { NM_ITEM,  "Load Font",      "F", 0, 0, 0,},
  274.   { NM_ITEM,  "Load File",      "L", 0, 0, 0,},
  275.   { NM_ITEM,  "Run File",       "R", 0, 0, 0,},
  276.   { NM_ITEM,  "Interactive",    "W", 0, 0, 0,},
  277.   { NM_TITLE, "Control",          0, 0, 0, 0,},
  278.   { NM_ITEM,  "Pause every page", 0, CHECKIT | CHECKED, 0, 0,},
  279.   { NM_ITEM,  "Continue after pause", "C", 0, 0, 0,},
  280.   { NM_ITEM,  "Interrupt",      "I", 0, 0, 0,},
  281.   { NM_ITEM,  "Kill",             0, 0, 0, 0,},
  282.   { NM_END,   NULL,               0, 0, 0, 0,},
  283. };
  284.  
  285. /* Arguments */
  286.  
  287. int arglen, argwb, argfilec, argsizec, argmemc;
  288. int argprint, argscreen, argiff, argint, argclosewb,
  289.   sunmouse_compat = FALSE;
  290. char *argbuf, *argsizev[5], *argmemv[5];
  291. char argfilev[5][256];
  292. char argifn[256];
  293. char *argcon;
  294. char *argkey[] =
  295. {   "IFF",
  296.     "SCREEN",
  297.     "PRINTER",
  298.     "INTERACTIVE",
  299.     "SIZE",
  300.     "MEM",
  301.     "CLOSEWB",
  302.     "CONDEV",
  303.     NULL
  304. };
  305.  
  306. /* Startup code */
  307.  
  308. extern void main(int argc, char **argv);
  309.  
  310. void _main(char *line)
  311. {   struct DiskObject *diskobj;
  312.     char *diskname;
  313.     char *argv[32];
  314.     int argc;
  315.  
  316.     /* If this is a workbench startup construct the arguments string.  We
  317.      * find the name of our icon from the first argument.  Then we laod the
  318.      * icon and look for an ARGS string in the tooltypes.  We concatenate
  319.      * the program name and the arguments into an Alloc'ed buffer */
  320.  
  321.     if (WBenchMsg && WBenchMsg->sm_NumArgs)
  322.     {   diskname = WBenchMsg->sm_ArgList[0].wa_Name;
  323.         line = NULL;
  324.         IconBase = OpenLibrary("icon.library", 0);
  325.         if (IconBase)
  326.         {   diskobj = GetDiskObject(diskname);
  327.             line = FindToolType(diskobj->do_ToolTypes, "ARGS");
  328.         }
  329.         if (line)
  330.         {   arglen = strlen(diskname) + strlen(line) + 2;
  331.             argbuf = AllocMem(arglen, MEMF_CLEAR);
  332.         }
  333.         if (argbuf)
  334.         {   strcpy(argbuf, diskname);
  335.             strcat(argbuf, " ");
  336.             strcat(argbuf, line);
  337.         }
  338.         line = argbuf;
  339.         if (diskobj)
  340.             FreeDiskObject(diskobj);
  341.         if (IconBase)
  342.             CloseLibrary((struct Library *) IconBase);
  343.     }
  344.  
  345.     /* Parse the arguments to break words and strip quotes.  N.B. the
  346.      * main program can determine that the arument was quoted by inspecting
  347.      * the preceeding character */
  348.  
  349.     argc = 0;
  350.     if (line == NULL) goto endline;
  351.     for (;;)
  352.     {   while (*line == ' ' || *line == '\t' || *line == '\n') line++;
  353.         if (*line == 0) break;
  354.         if (argc == 32)
  355.         {   argc = 0;
  356.             goto endline;
  357.         }
  358.         if (*line == '"')
  359.         {   argv[argc] = ++line;
  360.             while (*line != '"')
  361.             {   if (*line == 0)
  362.                 {   argc = 0;
  363.                     goto endline;
  364.                 }
  365.                 line++;
  366.             }
  367.         }
  368.         else
  369.         {   argv[argc] = line;
  370.             while (*line != ' ' && *line != '\t' && *line != '\n')
  371.             {   if (*line == 0)
  372.                 {   argc++;
  373.                     goto endline;
  374.                 }
  375.                 line++;
  376.             }
  377.         }
  378.         *line++ = 0;
  379.         argc++;
  380.     }
  381. endline:
  382.  
  383.     /* Set up the standard input/output files */
  384.  
  385.     if (WBenchMsg) /* Workbench startup, no files */
  386.     {   argwb = 1;
  387.     }
  388.     else           /* CLI startup, open stderr */
  389.     {   errfh = Open("*", MODE_OLDFILE);
  390.         if (errfh == NULL)
  391.         {   retcode = 20;
  392.             goto tidyexit;
  393.         }
  394.     }
  395.  
  396.     /* Call the main program  */
  397.  
  398.     main(argc, argv);
  399.  
  400.     /* Tidy up and exit */
  401.  
  402. tidyexit:
  403.     if (argbuf) FreeMem(argbuf, arglen);
  404.     if (errfh) Close(errfh);
  405.  
  406.     _XCEXIT(retcode);
  407. }
  408.  
  409. /* Main program */
  410.  
  411. void main(int argc, char **argv)
  412. {   struct IntuiMessage *msg;
  413.     struct Gadget *gadget;
  414.     char *s;
  415.     int *ip, i, ch;
  416.     int xsize, ysize, ssize, xoff, yoff, xden, yden, pden;
  417.     char fname[256];
  418.     static UWORD penspec[10] = {4, 5, 7, 12, 3, 13, 4, 0, 6, (UWORD) ~0};
  419.     BPTR oldlock, newlock;
  420.     int changed_dir = FALSE;
  421.     APTR *my_VisualInfo;  /* for GadTools stuff */
  422.  
  423.     process = (struct Process *) FindTask(NULL);
  424.     syswindow = (struct Window *) process->pr_WindowPtr;
  425.  
  426.     /* Open the libraries */
  427.  
  428.     GfxBase =
  429.         (struct GfxBase *)       OpenLibrary("graphics.library", 0);
  430.     IntuitionBase =
  431.         (struct IntuitionBase *) OpenLibrary("intuition.library", 0);
  432.     AslBase = OpenLibrary("asl.library", 37);
  433.     GadToolsBase = OpenLibrary("gadtools.library", 37);
  434.     if (GfxBase == NULL || IntuitionBase == NULL || AslBase == NULL
  435.     || GadToolsBase == NULL)
  436.     {   errmsg("can't open libraries (you need asl.library V37+)");
  437.         goto errorexit;
  438.     }
  439. # ifndef STATICLINK
  440.     PSbase = (struct library *) OpenLibrary("post.library", POSTVERNO);
  441.     if (PSbase == NULL)
  442.     {   errmsg("can't open post.library");
  443.         goto errorexit;
  444.     }
  445. # endif
  446.  
  447.     /* Parse the arguments and keywords.  See the usage string below */
  448.  
  449.     if (argc == 0) goto badargs;
  450.     argc--;
  451.     argv++;
  452.     if (argc == 0 || argwb) argint = 1;
  453.     if (argc == 1 && strcmp(*argv, "?") == 0) goto usage;
  454.  
  455.     while (argc--)
  456.     {   s = *argv++;
  457.         i = -1;
  458.         if (s[-1] != '"')
  459.             for (;;)
  460.             {   i++;
  461.                 if (argkey[i] == NULL)
  462.                 {   i = -1;
  463.                     break;
  464.                 }
  465.                 if (stricmp(s, argkey[i]) == 0) break;
  466.             }
  467.         switch (i)
  468.         {   case 0:    /* IFF */
  469.                 if (argc == 0 || strlen(*argv) >= 80) goto badargs;
  470.                 argc--;
  471.                 argiff = 1;
  472.                 strcpy(argifn, *argv++);
  473.                 break;
  474.  
  475.             case 1:    /* SCREEN */
  476.                 argscreen = 1;
  477.                 break;
  478.  
  479.             case 2:    /* PRINTER */
  480.                 argprint = 1;
  481.                 break;
  482.  
  483.             case 3:    /* INTERACTIVE */
  484.                 argint = 1;
  485.                 break;
  486.  
  487.             case 4:    /* SIZE */
  488.                 if (argc == 0) goto badargs;
  489.                 argc--;
  490.                 if (argsizec == 5) goto badargs;
  491.                 argsizev[argsizec++] = *argv++;
  492.                 break;
  493.  
  494.             case 5:    /* MEM */
  495.                 if (argc == 0) goto badargs;
  496.                 argc--;
  497.                 if (argmemc == 5) goto badargs;
  498.                 argmemv[argmemc++] = *argv++;
  499.                 break;
  500.  
  501.             case 6:    /* CLOSEWB */
  502.                 argclosewb = 1;
  503.                 break;
  504.  
  505.             case 7:    /* CONDEV */
  506.                 if (argc == 0) goto badargs;
  507.                 argc--;
  508.                 argcon = *argv++;
  509.                 break;
  510.  
  511.             default:
  512.                 if (argfilec == 5 || strlen(s) >= 80) goto badargs;
  513.                 strcpy(argfilev[argfilec++], s);
  514.         }
  515.     }
  516.     if (!argscreen && !argiff && !argint)  argprint = 1;
  517.     if (argscreen) argint = 1;
  518.  
  519.     /* Set up the screen size, adjusting for interlace */
  520.  
  521.     newscreen.Width = GfxBase->NormalDisplayColumns;
  522.     newscreen.Height = GfxBase->NormalDisplayRows * 2;
  523.     if (newscreen.Width < 400) newscreen.Width = 400;
  524.     if (newscreen.Height < 300) newscreen.Height = 300;
  525.  
  526.     /* Set up the default page size.  For printer output we get the defaults
  527.      * from preferences; otherwise we default to an A4 inch page at 75 dpi.
  528.      * with 3 colour planes, trimming the width to fit onto the screen.  (We
  529.      * can't quite fit A4 onto a standard 640 pixel wide screen - 8.24 inches
  530.      * instead of 8.26). */
  531.  
  532.     bitmap.BytesPerRow = 1;
  533.     bitmap.Rows = 1;
  534.     bitmap.Flags = 0;
  535.     bitmap.Depth = parm.page.depth = 3;
  536.     if (argprint)
  537.     {   setprinter();
  538.         if (prport == NULL)
  539.         {   errmsg("can't open printer device");
  540.             goto errorexit;
  541.         }
  542.     }
  543.     else
  544.     {   parm.page.xsize = 824 * 75 / 100;
  545.         parm.page.ysize = 1169 * 75 / 100;
  546.         parm.page.xoff = parm.page.yoff = 0;
  547.         parm.page.xden = parm.page.yden = 75;
  548.         if (parm.page.xsize > newscreen.Width - 22)
  549.             parm.page.xsize = newscreen.Width - 22;
  550.     }
  551.     parm.page.ydir = -1;
  552.  
  553.     /* Parse the "SIZE xyod..s..p.bc." options */
  554.  
  555.     xsize = ysize = ssize = xden = yden = pden = 0;
  556.     for (i = 0; i < argsizec; i++)
  557.     {   s = argsizev[i];
  558.         for (;;)
  559.         {   ch = *s++;
  560.             if (ch == 0) break;
  561.             ch = tolower(ch);
  562.             switch (ch)
  563.             {   case 'x':
  564.                     if      (tolower(*s) == 'o')
  565.                     {   s++;
  566.                         if (!strtoint(&s, &xoff)) goto badvalue;
  567.                         parm.page.xoff = xoff;
  568.                         continue;
  569.                     }
  570.                     else if (tolower(*s) == 'd')
  571.                     {   s++;
  572.                         ip = &xden;
  573.                     }
  574.                     else
  575.                         ip = &xsize;
  576.                     break;
  577.  
  578.                 case 'y':
  579.                     if      (tolower(*s) == 'o')
  580.                     {   s++;
  581.                         if (!strtoint(&s, &yoff)) goto badvalue;
  582.                         parm.page.yoff = yoff;
  583.                         continue;
  584.                     }
  585.                     else if (tolower(*s) == 'd')
  586.                     {   s++;
  587.                         ip = &yden;
  588.                     }
  589.                     else
  590.                         ip = &ysize;
  591.                     break;
  592.  
  593.                 case 's':
  594.                     ip = &ssize;
  595.                     break;
  596.  
  597.                 case 'p':
  598.                     ip = &pden;
  599.                     break;
  600.  
  601.                 case 'd':
  602.                 {   if (!strtoint(&s, &xden)) goto badvalue;
  603.                     yden = xden;
  604.                     continue;
  605.                 }
  606.  
  607.                 case 'b':
  608.                     parm.page.depth = 1;
  609.                     continue;
  610.  
  611.                 case 'c':
  612.                     ch = *s;
  613.                     if      (ch == '3')
  614.                     {   s++;
  615.                         parm.page.depth = 3;
  616.                     }
  617.                     else if (ch == '4')
  618.                     {   s++;
  619.                         parm.page.depth  = 4;
  620.                     }
  621.                     else
  622.                         parm.page.depth = 3;
  623.                     continue;
  624.  
  625.                 default:
  626.                     goto badvalue;
  627.             }
  628.             if (!strtoint(&s, ip)) goto badvalue;
  629.         }
  630.     }
  631.     if (xden != 0) parm.page.xden = xden;
  632.     if (yden != 0) parm.page.yden = yden;
  633.     if (xsize != 0) parm.page.xsize = xsize;
  634.     if (ysize != 0) parm.page.ysize = ysize;
  635.     if (pden != 0)
  636.     {   prden = pden;
  637.         if (argprint) setprintden();
  638.     }
  639.  
  640.     /* Set up the default memory sizes */
  641.  
  642.     parm.memvlen = defmemvlen;
  643.     parm.memflen = defmemflen;
  644.     parm.memllen = defmemllen;
  645.     parm.memhlen = defmemhlen;
  646.  
  647.     /* Parse the "MEM fhlv.." options */
  648.  
  649.     for (i = 0; i < argmemc; i++)
  650.     {   s = argmemv[i];
  651.         for (;;)
  652.         {   ch = *s++;
  653.             if (ch == 0) break;
  654.             ch = tolower(ch);
  655.             switch (ch)
  656.             {   case 'f':
  657.                     ip = &parm.memflen;
  658.                     break;
  659.  
  660.                 case 'h':
  661.                     ip = &parm.memhlen;
  662.                     break;
  663.  
  664.                 case 'l':
  665.                     ip = &parm.memllen;
  666.                     break;
  667.  
  668.                 case 'v':
  669.                     ip = &parm.memvlen;
  670.                     break;
  671.  
  672.                 default:
  673.                     goto badvalue;
  674.             }
  675.             if (!strtoint(&s, ip)) goto badvalue;
  676.         }
  677.     }
  678.  
  679.     /* We seem to have to explicitly load the font from the disk before
  680.      * Intuition can be depended upon to use it */
  681.  
  682.     if (argint)
  683.     {  DiskfontBase = OpenLibrary("diskfont.library", 0);
  684.        if (DiskfontBase)
  685.        {   textfont = OpenDiskFont(&topaz11);
  686.            CloseLibrary(DiskfontBase);
  687.        }
  688.        if (textfont == NULL)
  689.        {   errmsg("can't find font topaz/11");
  690.            goto errorexit;
  691.        }
  692.     }
  693.  
  694.     /* Set up the color map according to the number of bitplanes */
  695.  
  696. setcmap:
  697.     restarterror = 0;
  698.     if (!argint) newscreen.Depth = parm.page.depth;
  699.     colormap.Count = 1 << newscreen.Depth;
  700.     if      (newscreen.Depth == 1)
  701.         colormap.ColorTable = (APTR) bcolors;
  702.     else
  703.         colormap.ColorTable = (APTR) ccolors;
  704.  
  705.     /* Open the screen and load the color map  */
  706.  
  707.     if (argint)
  708.     {   screen = OpenScreenTags(&newscreen,
  709.                 SA_Left, 0,
  710.                 SA_Top, 0,
  711.                 SA_Depth, 4, /* ALWAYS open at 4 bpl */
  712.                 SA_Title, titlewait,
  713.                 SA_Font, &topaz11,
  714.                 SA_Type, CUSTOMSCREEN,
  715.                 SA_DisplayID, HIRESLACE_KEY | DEFAULT_MONITOR_ID,
  716.                 SA_Overscan, OSCAN_TEXT,
  717.                 SA_AutoScroll, FALSE,
  718.                 SA_Pens, penspec,
  719.                 TAG_DONE);
  720.         if (screen == NULL)
  721.         {   errmsg("can't open screen");
  722.             goto errorexit;
  723.         }
  724.         newerrwindow.Screen = screen;
  725.         newbitwindow.Screen = screen;
  726.         newintwindow.Screen = screen;
  727.     /* I've hardcoded LoadRGB4 to load in 16 colors always instead of
  728.        colormap.Count colors because I've decided to always use a
  729.        16 color screen.  -- R. Poole */
  730.         LoadRGB4(&screen->ViewPort,
  731.                  (short *) colormap.ColorTable, 16);
  732.         newerrwindow.Width = newscreen.Width;
  733.         errwindow = OpenWindow(&newerrwindow);
  734.         if (errwindow == NULL)
  735.         {   errmsg("can't open error window");
  736.             goto errorexit;
  737.         }
  738.         process->pr_WindowPtr = (APTR) errwindow;
  739.  
  740.     /* setup GadTools related stuff */
  741.     my_VisualInfo = GetVisualInfo(screen, TAG_END);
  742.     if (my_VisualInfo == NULL) {
  743.       errmsg("can't get visual info");
  744.       goto errorexit;
  745.     }
  746.     menu0 = CreateMenus(mainmenu, TAG_END);
  747.     LayoutMenus(menu0, my_VisualInfo, TAG_END);
  748.     menu1 = menu0->NextMenu;
  749.     menu2 = menu1->NextMenu;
  750.     }
  751.     restarterror = 1;
  752.  
  753. restart:
  754.     if (fatalerror) goto tidyexit;
  755.     retcode = 0;
  756.     tidyup();
  757.  
  758.     if (argint)
  759.     {   if (argclosewb) CloseWorkBench();
  760.         if (requested == 0)
  761.         {
  762.             /* Put up the parameters requestor (window) */
  763.             if (OpenReqWindow(screen) > 0)
  764.             {   errmsg("can't open parameters window");
  765.                 goto restart;
  766.             }
  767.             setreqgadgets();
  768.  
  769.             /* Loop handling gadget messages */
  770.  
  771.             for (;;)
  772.             {   WaitPort(ReqWnd->UserPort);
  773.                 while (msg = GT_GetIMsg(ReqWnd->UserPort))
  774.                 {   gadget = (struct Gadget *) msg->IAddress;
  775.                     i = gadget->GadgetID;
  776.                     switch (i)
  777.                     {   case GD_okgad:
  778.                         case GD_cancelgad:
  779.                             goto closereq;
  780.  
  781.                         case GD_Output:
  782.                 switch (msg->Code) {
  783.                 case 0:
  784.                   argiff = FALSE;
  785.                   argprint = TRUE;
  786.                   break;
  787.                 case 1:
  788.                   argiff = FALSE;
  789.                   argprint = FALSE;
  790.                   argscreen = TRUE;
  791.                   parm.page.xden = 75;
  792.                   parm.page.yden = 75;
  793.                   parm.page.xsize = 824 * 75 / 100;
  794.                   parm.page.ysize = 1169 * 75 / 100;
  795.                   if (parm.page.xsize > newscreen.Width - 22)
  796.                 parm.page.xsize = newscreen.Width - 22;
  797.                   break;
  798.                 case 2:
  799.                   argiff = TRUE;
  800.                   argprint = FALSE;
  801.                   break;
  802.                 }
  803.                             if (argprint)
  804.                             {    setprinter();
  805.                                  if (prport == NULL)
  806.                                  {   argprint = 0;
  807.                                      errmsg("can't open printer device");
  808.                                      i = GD_restart;
  809.                                      goto closereq;
  810.                                  }
  811.                             }
  812.                 setreqgadgets();
  813.                 break;
  814.  
  815.                         case GD_density:
  816.                             if (argprint)
  817.                             {   prden = msg->Code + 1;
  818.                 /* print density is a cycle gadget, and
  819.                    cycle gadget values are returned in
  820.                    the Code field */
  821.                                 setprintden();
  822.                                 setreqgadgets();
  823.                             }
  824.                             break;
  825.  
  826.                         case GD_Colours:
  827.                 switch(msg->Code) {
  828.                 case 0:
  829.                   parm.page.depth = 1;
  830.                   break;
  831.                 case 1:
  832.                   parm.page.depth = 3;
  833.                   break;
  834.                 case 2:
  835.                   parm.page.depth = 4;
  836.                   break;
  837.                 }
  838.                 break;
  839.  
  840.               case GD_wbclose:
  841.                 if (gadget->Flags & GFLG_SELECTED) {
  842.                   argclosewb = TRUE;
  843.                 }
  844.                 else {
  845.                   argclosewb = FALSE;
  846.                 }
  847.                 break;
  848.  
  849.               case GD_sunmouse:
  850.                 if (gadget->Flags & GFLG_SELECTED) {
  851.                   sunmouse_compat = TRUE;
  852.                 }
  853.                 else {
  854.                   sunmouse_compat = FALSE;
  855.                 }
  856.                 break;
  857.  
  858.                         case GD_fontmem:
  859.               case GD_htonemem:
  860.               case GD_VMem:
  861.               case GD_pathmem:
  862.               case GD_xsize:
  863.               case GD_ysize:
  864.               case GD_xdpi:
  865.               case GD_ydpi:
  866.                             getgadgabs(gadget);
  867.                 break;
  868.                     }
  869.                     GT_ReplyIMsg(msg);
  870.                 }
  871.             }
  872.  
  873.             /* Close the requester window */
  874.  
  875. closereq:   getreqgadgets();
  876.         while (msg)
  877.             {   GT_ReplyIMsg(msg);
  878.                 msg = GT_GetIMsg(ReqWnd->UserPort);
  879.             }
  880.             CloseReqWindow();
  881.  
  882.             if (i == GD_cancelgad) goto tidyexit;
  883.             if (i == GD_restart) goto restart;
  884.  
  885.             /* If we have changed our mind about the number of bitplanes
  886.              * close the screen and go back to reopen it with the new depth
  887.              */
  888.  
  889.             if (parm.page.depth != newscreen.Depth)
  890.             {   process->pr_WindowPtr = (APTR) syswindow;
  891.                 CloseWindow(errwindow);
  892.                 errwindow = NULL;
  893.         FreeMenus(menu0);
  894.         FreeVisualInfo(my_VisualInfo);
  895.                 CloseScreen(screen);
  896.                 screen = NULL;
  897.                 newscreen.Depth = parm.page.depth;
  898.                 requested = 1;
  899.                 goto setcmap;
  900.             }
  901.         }
  902.         requested = 0;
  903.     }
  904.  
  905.     /* Set the size of the interactive windows */
  906.  
  907.     if (argint)
  908.     {   newbitwindow.Width = newscreen.Width;
  909.         newbitwindow.Height = newscreen.Height -
  910.             newintwindow.TopEdge - newintwindow.Height;
  911.         newbitwindow.TopEdge = newscreen.Height -
  912.             newbitwindow.Height;
  913.         newintwindow.Width = newscreen.Width;
  914.         newintwindow.MaxHeight = newscreen.Height -
  915.             newintwindow.TopEdge - newbitwindow.MinHeight;
  916.  
  917.     /* Locate the visible part of the bitmap within its window, adjusting
  918.      * for the borders */
  919.  
  920.         winxbase = 4;
  921.         winybase = 2;
  922.         winxsize = newbitwindow.Width - 22;
  923.         winysize = newbitwindow.Height - 12;
  924.  
  925.     /* Set the page size.  It must not be smaller than the interior of the
  926.      * interactive window.  We may not need the horizontal scroll bar.  Each
  927.      * bitmap row must start on a word boundary */
  928.  
  929.         if (parm.page.xsize <= winxsize)
  930.         {   winysize += 8;
  931.             vscrollgadg.NextGadget = 0;
  932.             vscrollgadg.Height = 0;
  933.         }
  934.         else
  935.         {   vscrollgadg.NextGadget = &hscrollgadg;
  936.             vscrollgadg.Height = -8;
  937.         }
  938.         if (parm.page.xsize < winxsize) parm.page.xsize = winxsize;
  939.         if (parm.page.ysize < winysize) parm.page.ysize = winysize;
  940.     }
  941.     parm.page.ybase = 0;
  942.     parm.page.yheight = parm.page.ysize;
  943.     if (!argint)
  944.         if (ssize != 0 && ssize < parm.page.ysize) parm.page.ysize = ssize;
  945.     if (parm.page.xsize == 0 || parm.page.ysize == 0)
  946.     {   errmsg("page size not set in preferences");
  947.         goto restart;
  948.     }
  949.     parm.page.xbytes = (parm.page.xsize + 15) >> 3 & 0xfffffffe;
  950.     parm.page.len = parm.page.xbytes * parm.page.ysize;
  951.  
  952.     /* Allocate the page buffer.  It  must be in chip memory if we are
  953.      * outputting to a screen */
  954.  
  955.     for (i = 0; i < parm.page.depth; i++)
  956.     {   if ((parm.page.buf[i] = AllocMem(parm.page.len,
  957.                  (argscreen ? MEMF_CHIP|MEMF_CLEAR :
  958.                               MEMF_PUBLIC|MEMF_CLEAR))) == NULL)
  959.         {   errmsg("can't get page buffer");
  960.             goto restart;
  961.         }
  962.     }
  963.  
  964.     /* Initialise the bitmap */
  965.  
  966.     bitmap.BytesPerRow = parm.page.xbytes;
  967.     bitmap.Rows = parm.page.ysize;
  968.     bitmap.Flags = 0;
  969.     bitmap.Depth = parm.page.depth;
  970.     memcpy((char *) bitmap.Planes, (char *) parm.page.buf,
  971.            sizeof bitmap.Planes);
  972.  
  973.     /* For interactive working, set up the windows */
  974.  
  975.     if (argint)
  976.     {
  977.         /* Finish initialising the gadgets and open the windows */
  978.  
  979.         hscrollinfo.HorizPot = 0;
  980.         vscrollinfo.VertPot = 0xffff;
  981.         hscrollinfo.HorizBody = (0xffff * winxsize) / parm.page.xsize;
  982.         vscrollinfo.VertBody = (0xffff * winysize) / parm.page.ysize;
  983.         winxpos = 0;
  984.         winypos = parm.page.ysize - winysize;
  985.         bitwindow = OpenWindow(&newbitwindow);
  986.         intwindow = OpenWindow(&newintwindow);
  987.         if (bitwindow == NULL || intwindow == NULL)
  988.         {   errmsg("can't open windows");
  989.             goto restart;
  990.         }
  991.     /* set up the file requesters */
  992.     /* I have replaced all ARP-isms with 2.0+ features, including the
  993.        ASL file requesters.  Some people don't like the way the ASL
  994.        requesters look; I happen to think they look great.  More
  995.        importantly, ASL.library improves with each release of the OS.
  996.        Best not to rely on non-standard libraries. R. Poole 1/30/93 */
  997.         filereq1 = (struct FileRequester *)
  998.       AllocAslRequestTags(ASL_FileRequest,
  999.                   ASL_Hail, "Select file to load",
  1000.                   ASL_Window, intwindow,
  1001.                   ASL_LeftEdge, 20,
  1002.                   ASL_TopEdge,  20,
  1003.                   ASL_OKText, "Load",
  1004.                   ASL_FuncFlags, FILF_PATGAD | FILF_NEWIDCMP,
  1005.                   ASL_Pattern, "~(#?.info)",
  1006.                   TAG_DONE);
  1007.         filereq2 = (struct FileRequester *)
  1008.       AllocAslRequestTags(ASL_FileRequest,
  1009.                   ASL_Hail, "Select file to load",
  1010.                   ASL_Window, intwindow,
  1011.                   ASL_LeftEdge, 20,
  1012.                   ASL_TopEdge,  20,
  1013.                   ASL_OKText, "Load",
  1014.                   ASL_FuncFlags, FILF_PATGAD | FILF_NEWIDCMP,
  1015.                   ASL_Pattern, "#?.ps",
  1016.                   TAG_DONE);
  1017.  
  1018.         if (filereq1 == NULL || filereq2 == NULL)
  1019.         {   errmsg("can't get file requestors");
  1020.             goto errorexit;
  1021.         }
  1022.  
  1023.  
  1024.         /* Set up new console streams.  Black on white characters */
  1025.  
  1026.         if (argcon == NULL)
  1027.                 argcon = "CON://///WINDOW"; /* Workbench 2.0 */
  1028.         sprintf((char *) undobuff, "%s%lx", argcon, intwindow);
  1029.         confh = Open((char *) undobuff, MODE_OLDFILE);
  1030.         if (confh == NULL)
  1031.         {   errmsg("can't open console handler");
  1032.             goto restart;
  1033.         }
  1034.         FPrintf(confh, "\x9b\x33\x37\x6d");
  1035.     }
  1036.  
  1037.         /* Create the menu handler task */
  1038.  
  1039.     if (argint)
  1040.     {   mainport = CreatePort(NULL, 0);
  1041.         if (mainport)
  1042.         {   menumsg.ExecMessage.mn_ReplyPort = mainport;
  1043.             menumsg.action = PSACTOPEN;
  1044.             menumsg.bitmap = &bitmap;
  1045.             menutask = CreateTask("post.menu", 6, (APTR) menuproc, 2000);
  1046.         }
  1047.         if (menutask)
  1048.             sendmenu(PSACTOPEN);
  1049.         if (menutask == NULL)
  1050.         {   errmsg("can't create menu handler");
  1051.             goto restart;
  1052.         }
  1053.     }
  1054.  
  1055.     /* Initialise for interpretation */
  1056.  
  1057.     insertbreak();
  1058.     SetExcept(~0, SIGBREAKF_CTRL_C);
  1059.     breakset = 1;
  1060.     insertftrap();
  1061.     ftrapset = 1;
  1062.  
  1063. #ifndef STATICLINK
  1064.     parm.flushfunc = (APTR) flushpage;
  1065.     parm.copyfunc = (APTR) copypage;
  1066. #endif
  1067.  
  1068.     if (argint)
  1069.     {   parm.infh = confh;
  1070.         parm.outfh = confh;
  1071.         parm.errfh = confh;
  1072.     }
  1073.     else
  1074.     {   parm.infh = Input();
  1075.         parm.outfh = Output();
  1076.         parm.errfh = errfh;
  1077.     }
  1078.  
  1079.     arec = PScreateact(&parm);
  1080.     if (arec == 0)
  1081.     {   errmsg("can't get memory");
  1082.         retcode = 20;
  1083.         goto restart;
  1084.     }
  1085.     if ((unsigned) arec <= errmax) retcode = 10;
  1086.  
  1087.     /* Interpret the argument files */
  1088.  
  1089.     for (i = 0; i < 5; i++)
  1090.     {   s = argfilev[i];
  1091.         if (s[0] != 0)
  1092.         {   if (retcode != 0) break;
  1093.             errcode =
  1094.                 PSintstring(arec, s, -1, 
  1095.                     (strcmp(s , "*") == 0 ?
  1096.                         PSFLAGFILE|PSFLAGCLEAR|PSFLAGERASE|PSFLAGINTER :
  1097.                         PSFLAGFILE|PSFLAGCLEAR|PSFLAGERASE));
  1098.             if (errcode) retcode = 10;
  1099.         }
  1100.     }
  1101.  
  1102.     /* Execute menu commands */
  1103.  
  1104.     if (argint)
  1105.     {   for (;;)
  1106.         {   sendmenu(retcode == 0 ? PSACTCOMMAND : PSACTEXIT);
  1107.             s = menumsg.string;
  1108.             switch (menumsg.command)
  1109.             {   case PSCOMQUIT:
  1110.                     goto quit;
  1111.  
  1112.                 case PSCOMRESTART:
  1113.                     PSdeleteact(arec);
  1114.                     arec = 0;
  1115.                     goto restart;
  1116.  
  1117.                 case PSCOMFILEF:
  1118.                     i = PSFLAGFILE|PSFLAGCLEAR|PSFLAGERASE;
  1119.                     filereq = filereq1;
  1120.                     if (AslRequestTags(filereq,
  1121.                        ASL_Hail, hailfilef,
  1122.                        ASL_Dir, "PSFonts:",
  1123.                        TAG_DONE) == NULL) break;
  1124.                     goto freq;
  1125.  
  1126.                 case PSCOMFILEL:
  1127.                     i = PSFLAGFILE|PSFLAGCLEAR|PSFLAGERASE;
  1128.                     filereq = filereq2;
  1129.             if (AslRequestTags(filereq,
  1130.                        ASL_Hail, hailfilen,
  1131.                        TAG_DONE) == NULL) break;
  1132.                     goto freq;
  1133.  
  1134.                 case PSCOMFILER:
  1135.                     i = PSFLAGFILE|PSFLAGCLEAR|PSFLAGERASE|PSFLAGSAVE;
  1136.                     filereq = filereq2;
  1137.             if (AslRequestTags(filereq,
  1138.                        ASL_Hail, hailfiles,
  1139.                        ASL_OKText, "Run",
  1140.                        TAG_DONE) == NULL) break;
  1141.             /* we want to put a shared read lock on the path
  1142.                so we can temporarily cd to it if we're `running'
  1143.                a PostScript file... this allows us to do nifty
  1144.                stuff like run a PS file that itself runs other
  1145.                PS files (see chess.ps and cheq.ps) */
  1146.             /* R. Poole -- 2/1/93 */
  1147.             newlock = Lock(filereq->rf_Dir, ACCESS_READ);
  1148.             oldlock = CurrentDir(newlock);
  1149.             changed_dir = TRUE;
  1150.                     /* Changed 2/7/93 because I discovered that if the
  1151.                        file requester doesn't return a full path in
  1152.                        filereq->rf_Dir, Post couldn't find the file!  Easy
  1153.                        fix: since I already put in the code to cd to the
  1154.                        directory where the file is located, just have
  1155.                        Post read the filename without prepending a
  1156.                        directory */
  1157.                     strcpy(fname, filereq->rf_File);
  1158.                     goto freq2;
  1159.  
  1160. freq:               TackOn(fname, filereq->rf_Dir, filereq->rf_File);
  1161. freq2:              PSintstring(arec, fname, -1, i);
  1162.             if (changed_dir) {
  1163.               CurrentDir(oldlock);
  1164.               UnLock(newlock);
  1165.               changed_dir = FALSE;
  1166.             }
  1167.                     break;
  1168.  
  1169.                 case PSCOMINTER:
  1170.                     PSintstring(arec, "%stdin", -1, 
  1171.                         PSFLAGFILE|PSFLAGCLEAR|PSFLAGERASE|PSFLAGSAVE|
  1172.                         PSFLAGINTER);
  1173.                     break;
  1174.             }
  1175.         }
  1176.     }
  1177.  
  1178. quit:
  1179.     PSdeleteact(arec);
  1180.     arec = 0;
  1181.     goto tidyexit;
  1182.  
  1183.     /* Argument errors and usage query */
  1184.  
  1185. badargs:
  1186.     errmsg("arguments bad, or value missing or too long");
  1187.     goto badusage;
  1188.  
  1189. badvalue:
  1190.     errmsg("argument bad value");
  1191.  
  1192. badusage:
  1193.     retcode = 20;
  1194.  
  1195. usage:
  1196.     if (!argwb) FPrintf(errfh, "post: usage:\n"
  1197.     "    post [files...] [IFF file] [SCREEN] [PRINTER] [INTERACTIVE]\n"
  1198.     "         [SIZE xyod..s..p.bc.] [MEM fhlv..] [CLOSEWB] [CONDEV con]\n");
  1199.     goto tidyexit;
  1200.  
  1201.     /* Tidy up and exit */
  1202.  
  1203. errorexit:
  1204.     retcode = 20;
  1205.  
  1206. tidyexit:
  1207.     FreeAslRequest(filereq1);
  1208.     FreeAslRequest(filereq2);
  1209.  
  1210.     tidyup();
  1211.  
  1212.     process->pr_WindowPtr = (APTR) syswindow;
  1213.     if (errwindow) CloseWindow(errwindow);
  1214.     /* New -- close down and free up GadTools menu */
  1215.     FreeMenus(menu0);
  1216.     /* New -- free VisualInfo since it's no longer needed */
  1217.     FreeVisualInfo(my_VisualInfo);
  1218.     if (screen) CloseScreen(screen);
  1219.  
  1220.     if (textfont) CloseFont(textfont);
  1221.  
  1222.     if (propen) CloseDevice((struct IORequest *) &prreq);
  1223.     if (prport) DeletePort(prport);
  1224.  
  1225. # ifndef STATICLINK
  1226.     if (PSbase)  CloseLibrary((struct Library *) PSbase);
  1227. # endif
  1228.     if (GadToolsBase) CloseLibrary((struct Library *) GadToolsBase);
  1229.     if (AslBase) CloseLibrary((struct Library *) AslBase);
  1230.     if (GfxBase) CloseLibrary((struct Library *) GfxBase);
  1231.     if (IntuitionBase)
  1232.     {   OpenWorkBench();
  1233.         CloseLibrary((struct Library *) IntuitionBase);
  1234.     }
  1235. }
  1236.  
  1237. /* Display an error requestor or message */
  1238.  
  1239. struct IntuiText bodytext2 =
  1240. {   AUTOFRONTPEN, AUTOBACKPEN, AUTODRAWMODE,
  1241.     AUTOLEFTEDGE + 32, AUTOTOPEDGE + 11,
  1242.     AUTOITEXTFONT, NULL, NULL };
  1243. struct IntuiText bodytext =
  1244. {   AUTOFRONTPEN, AUTOBACKPEN, AUTODRAWMODE,
  1245.     AUTOLEFTEDGE, AUTOTOPEDGE,
  1246.     AUTOITEXTFONT, POSTVER " Error", &bodytext2 };
  1247. struct IntuiText postext =
  1248. {   AUTOFRONTPEN, AUTOBACKPEN, AUTODRAWMODE,
  1249.     AUTOLEFTEDGE, AUTOTOPEDGE,
  1250.     AUTOITEXTFONT, "RETRY", NULL };
  1251. struct IntuiText negtext =
  1252. {   AUTOFRONTPEN, AUTOBACKPEN, AUTODRAWMODE,
  1253.     AUTOLEFTEDGE, AUTOTOPEDGE,
  1254.     AUTOITEXTFONT, "CANCEL", NULL };
  1255.  
  1256. void errmsg(char *string)
  1257. {   int width;
  1258.     if (IntuitionBase && (errwindow || argwb || AslBase == NULL))
  1259.     {   bodytext2.IText = string;
  1260.         width = IntuiTextLength(&bodytext2) + 70;
  1261.         if (width < 200) width = 200;
  1262.         if (!AutoRequest(errwindow, &bodytext,
  1263.                 (restarterror ? &postext : NULL), &negtext,
  1264.                 0, 0, width, 70))
  1265.             fatalerror = 1;
  1266.         return;
  1267.     }
  1268.     if (AslBase && !argwb)
  1269.     {   FPrintf(errfh, "post: %s\n", string);
  1270.         fatalerror = 1;
  1271.         return;
  1272.     }
  1273.     fatalerror = 1;
  1274. }
  1275.  
  1276. /* Tidy up */
  1277.  
  1278. void tidyup(void)
  1279. {   int i;
  1280.  
  1281.     if (breakset)
  1282.     {   SetExcept(0, SIGBREAKF_CTRL_C);
  1283.         deletebreak();
  1284.         breakset = 0;
  1285.     }
  1286.     if (ftrapset)
  1287.     {   deleteftrap();
  1288.         ftrapset = 0;
  1289.     }
  1290.  
  1291.     if (menuport)
  1292.         sendmenu(PSACTCLOSE);
  1293.     if (mainport)
  1294.     {   DeletePort(mainport);
  1295.         mainport = NULL;
  1296.     }
  1297.  
  1298.     if (confh)
  1299.     {   Close(confh);
  1300.         confh = NULL;
  1301.     }
  1302.  
  1303.     /* N.B. some versions of ConMan close the window themselves, so we
  1304.      * don't close the interactive window it it appears to have been
  1305.      * closed already */
  1306.  
  1307.     if (bitwindow)
  1308.     {   CloseWindow(bitwindow);
  1309.         bitwindow = NULL;
  1310.     }
  1311.     if (intwindow)
  1312.     {   if (screen->FirstWindow == intwindow ||
  1313.             errwindow->NextWindow == intwindow) CloseWindow(intwindow);
  1314.         intwindow = NULL;
  1315.     }
  1316.  
  1317.     for (i = 0; i < parm.page.depth; i++)
  1318.         if (parm.page.buf[i])
  1319.         {   FreeMem(parm.page.buf[i], parm.page.len);
  1320.             parm.page.buf[i] = NULL;
  1321.         }
  1322. }
  1323.  
  1324. /* Open the printer device and set up the page size */
  1325.  
  1326. void setprinter(void)
  1327. {   if (propen == 0)
  1328.     {   if (OpenDevice("printer.device", 0,
  1329.                        (struct IORequest *) &prreq, 0) != 0)
  1330.             return;
  1331.         propen = 1;
  1332.     }
  1333.     if (prport == NULL)
  1334.     {   prport = CreatePort(NULL, 0);
  1335.         if (prport == NULL) return;
  1336.         prreq.io_Message.mn_ReplyPort = prport;
  1337.         prsig = 1 << prport->mp_SigBit;
  1338.         prdata = (struct PrinterData *) prreq.io_Device;
  1339.         prextdata = &prdata->pd_SegmentData->ps_PED;
  1340.         prprefs = &prdata->pd_Preferences;
  1341.         prden = prprefs->PrintDensity;
  1342.     }
  1343.     if ((prprefs->PrintShade & SHADE_COLOR) == 0) parm.page.depth = 1;
  1344.     setprintden();
  1345. }
  1346.  
  1347. /* Set the printer density */
  1348.  
  1349. void setprintden(void)
  1350. {   int pxsize, pysize, xy;
  1351.  
  1352.     /* New density, call the device driver to change its extended data.  No
  1353.      * error check */
  1354.  
  1355.     if (prden > 7) prden = 7;
  1356.     if (prden != prprefs->PrintDensity)
  1357.     {   prreq.io_Command = PRD_DUMPRPORT;
  1358.         prrast.BitMap = &bitmap;
  1359.         prreq.io_RastPort = &prrast;
  1360.         prreq.io_ColorMap = (struct ColorMap *) &colormap;
  1361.         prreq.io_Modes = 0;
  1362.         prreq.io_SrcX = 0;
  1363.         prreq.io_SrcY = 0;
  1364.         prreq.io_SrcWidth = 1;
  1365.         prreq.io_SrcHeight = 1;
  1366.         prreq.io_DestCols = 1;
  1367.         prreq.io_DestRows = 1;
  1368.         prreq.io_Special = (SPECIAL_DENSITY1 * prden) | SPECIAL_NOPRINT;
  1369.         prprefs->PrintDensity = prden;
  1370.         DoIO((struct IORequest *) &prreq);
  1371.     }
  1372.  
  1373.     /* Extract the page size and density from the printer device preferences
  1374.      * and extended data */
  1375.  
  1376.     parm.page.xden = prextdata->ped_XDotsInch;
  1377.     parm.page.yden = prextdata->ped_YDotsInch;
  1378.     if      (prprefs->PrintFlags & PIXEL_DIMENSIONS)
  1379.     {   pxsize = prprefs->PrintMaxWidth;
  1380.         pysize = prprefs->PrintMaxHeight;
  1381.     }
  1382.     else if (prprefs->PrintFlags &
  1383.                 (BOUNDED_DIMENSIONS|ABSOLUTE_DIMENSIONS))
  1384.     {   pxsize = prprefs->PrintMaxWidth * parm.page.xden / 10;
  1385.         pysize = prprefs->PrintMaxHeight * parm.page.yden / 10;
  1386.     }
  1387.     if (prprefs->PrintAspect & ASPECT_VERT)
  1388.     {   xy = pxsize;
  1389.         pxsize = pysize;
  1390.         pysize = xy;
  1391.     }
  1392.     if (pxsize != 0) parm.page.xsize = pxsize;
  1393.     if (pysize != 0) parm.page.ysize = pysize;
  1394.     parm.page.xoff = 0;
  1395.     parm.page.yoff = 0;
  1396. }
  1397.  
  1398. /* Set all requester gadgets */
  1399.  
  1400. void setreqgadgets(void)
  1401. {
  1402.   int j;
  1403.  
  1404.   if (argiff) {
  1405.     GT_SetGadgetAttrs(ReqGadgets[GDX_iffname], ReqWnd, NULL,
  1406.               GTST_String, argifn,
  1407.               TAG_END);
  1408.   }
  1409.   if (argfilec > 0) {
  1410.     for (j = 0; j < argfilec; j++) {
  1411.       GT_SetGadgetAttrs(ReqGadgets[GDX_startup1 + j], ReqWnd, NULL,
  1412.             GTST_String, argfilev[j],
  1413.             TAG_END);
  1414.     }
  1415.   }
  1416.  
  1417.   switch (parm.page.depth) {
  1418.   case 1:
  1419.     GT_SetGadgetAttrs(ReqGadgets[GDX_Colours], ReqWnd, NULL,
  1420.               GTMX_Active, 0,
  1421.               TAG_END);
  1422.     break;
  1423.   case 3:
  1424.     GT_SetGadgetAttrs(ReqGadgets[GDX_Colours], ReqWnd, NULL,
  1425.               GTMX_Active, 1,
  1426.               TAG_END);
  1427.     break;
  1428.   case 4:
  1429.     GT_SetGadgetAttrs(ReqGadgets[GDX_Colours], ReqWnd, NULL,
  1430.               GTMX_Active, 2,
  1431.               TAG_END);
  1432.     break;
  1433.   }
  1434.  
  1435.   GT_SetGadgetAttrs(ReqGadgets[GDX_density], ReqWnd, NULL,
  1436.             GTCY_Active, prden - 1,
  1437.             TAG_END);
  1438.  
  1439.   setgadgint(ReqGadgets[GDX_xsize], parm.page.xsize);
  1440.   setgadgint(ReqGadgets[GDX_ysize], parm.page.ysize);
  1441.   setgadgint(ReqGadgets[GDX_offx], parm.page.xoff);
  1442.   setgadgint(ReqGadgets[GDX_offy], parm.page.yoff);
  1443.   setgadgint(ReqGadgets[GDX_xdpi], parm.page.xden);
  1444.   setgadgint(ReqGadgets[GDX_ydpi], parm.page.yden);
  1445.  
  1446.   if (argprint) {
  1447.     GT_SetGadgetAttrs(ReqGadgets[GDX_Output], ReqWnd, NULL,
  1448.               GTMX_Active, 0,
  1449.               TAG_END);
  1450.   }
  1451.   else {
  1452.     if (argiff) {
  1453.       GT_SetGadgetAttrs(ReqGadgets[GDX_Output], ReqWnd, NULL,
  1454.             GTMX_Active, 2,
  1455.             TAG_END);
  1456.     }
  1457.     else {
  1458.       GT_SetGadgetAttrs(ReqGadgets[GDX_Output], ReqWnd, NULL,
  1459.             GTMX_Active, 1,
  1460.             TAG_END);
  1461.     }
  1462.   }
  1463.  
  1464.   setgadgcbox(ReqGadgets[GDX_wbclose], argclosewb);
  1465.   setgadgcbox(ReqGadgets[GDX_sunmouse], sunmouse_compat);
  1466.  
  1467.   setgadgint(ReqGadgets[GDX_fontmem], parm.memflen);
  1468.   setgadgint(ReqGadgets[GDX_htonemem], parm.memhlen);
  1469.   setgadgint(ReqGadgets[GDX_VMem], parm.memvlen);
  1470.   setgadgint(ReqGadgets[GDX_pathmem], parm.memllen);
  1471.  
  1472.   enablegadg(ReqGadgets[GDX_density], argprint);
  1473. }
  1474.  
  1475. /* Get all requester gadgets */
  1476.  
  1477. void getreqgadgets(void)
  1478. {
  1479.   int j;
  1480.  
  1481.   strcpy(argifn, ((struct StringInfo *) ReqGadgets[GDX_iffname]->SpecialInfo)->Buffer);
  1482.   if (argifn[0] == 0) {
  1483.     argiff = 0;
  1484.   }
  1485.  
  1486.   strcpy(argfilev[0], ((struct StringInfo *) ReqGadgets[GDX_startup1]->SpecialInfo)->Buffer);
  1487.   strcpy(argfilev[1], ((struct StringInfo *) ReqGadgets[GDX_startup2]->SpecialInfo)->Buffer);
  1488.   strcpy(argfilev[2], ((struct StringInfo *) ReqGadgets[GDX_startup3]->SpecialInfo)->Buffer);
  1489.   strcpy(argfilev[3], ((struct StringInfo *) ReqGadgets[GDX_startup4]->SpecialInfo)->Buffer);
  1490.   strcpy(argfilev[4], ((struct StringInfo *) ReqGadgets[GDX_startup5]->SpecialInfo)->Buffer);
  1491.  
  1492.   for (j = 0; j < 5; j++) {
  1493.     if (argfilev[j][0] != '\0') {
  1494.       argfilec = j+1;
  1495.     }
  1496.   }
  1497.  
  1498.   argclosewb = getgadgcbox(ReqGadgets[GDX_wbclose]);
  1499.   sunmouse_compat = getgadgcbox(ReqGadgets[GDX_sunmouse]);
  1500.   parm.page.xsize = getgadgabs(ReqGadgets[GDX_xsize]);
  1501.   parm.page.ysize = getgadgabs(ReqGadgets[GDX_ysize]);
  1502.   parm.page.xoff = getgadgint(ReqGadgets[GDX_offx]);
  1503.   parm.page.yoff = getgadgint(ReqGadgets[GDX_offy]);
  1504.   parm.page.xden = getgadgabs(ReqGadgets[GDX_xdpi]);
  1505.   parm.page.yden = getgadgabs(ReqGadgets[GDX_ydpi]);
  1506.   parm.memflen = getgadgabs(ReqGadgets[GDX_fontmem]);
  1507.   parm.memhlen = getgadgabs(ReqGadgets[GDX_htonemem]);
  1508.   parm.memvlen = getgadgabs(ReqGadgets[GDX_VMem]);
  1509.   parm.memllen = getgadgabs(ReqGadgets[GDX_pathmem]);
  1510. }
  1511.  
  1512. /* Enable a gadget */
  1513.  
  1514. void enablegadg(struct Gadget *gadget, int enable)
  1515. {
  1516.   GT_SetGadgetAttrs(gadget, ReqWnd, NULL,
  1517.             GA_Disabled, !enable,
  1518.             TAG_END);
  1519. }
  1520.  
  1521. /* Set the value of a CheckBox requester gadget */
  1522.  
  1523. void setgadgcbox(struct Gadget *gadget, int value)
  1524. {
  1525.   GT_SetGadgetAttrs(gadget, ReqWnd, NULL,
  1526.             GTCB_Checked, value,
  1527.             TAG_END);
  1528. }
  1529.  
  1530. /* Get the value of a CheckBox gadget */
  1531.  
  1532. int getgadgcbox(struct Gadget *gadget)
  1533. {   return ((gadget->Flags & GFLG_SELECTED) != 0);
  1534. }
  1535.  
  1536. /* Set the value of an integer requester gadget */
  1537.  
  1538. void setgadgint(struct Gadget *gadget, int value)
  1539. {
  1540.   GT_SetGadgetAttrs(gadget, ReqWnd, NULL,
  1541.             GTIN_Number, value,
  1542.             TAG_END);
  1543. }
  1544.  
  1545. /* Get the value of an integer gadget */
  1546.  
  1547. int getgadgint(struct Gadget *gadget)
  1548. {   struct StringInfo *info = (struct StringInfo *) gadget->SpecialInfo;
  1549.     return (int) info->LongInt;
  1550. }
  1551.  
  1552. /* Get the absolute value of an integer gadget */
  1553.  
  1554. int getgadgabs(struct Gadget *gadget)
  1555. {   int value = getgadgint(gadget);
  1556.     if (value < 0)
  1557.     {   value = 0;
  1558.         setgadgint(gadget, value);
  1559.     }
  1560.     return value;
  1561. }
  1562.  
  1563. /* String to integer conversion; digits only, with error check */
  1564.  
  1565. int strtoint(char **sp, int *ip)
  1566. {   char *s = *sp;
  1567.     int i = 0;
  1568.     int ch;
  1569.     for (;;)
  1570.     {   ch = *s;
  1571.         if (ch < '0' || ch > '9') break;
  1572.         i = i * 10 + (ch - '0');
  1573.         s++;
  1574.     }
  1575.     if (s == *sp)
  1576.         return 0;
  1577.     else
  1578.     {   *sp = s;
  1579.         *ip = i;
  1580.         return 1;
  1581.     }
  1582. }
  1583.  
  1584. /* Send a mesage to the menu handler task */
  1585.  
  1586. void sendmenu(int action)
  1587. {   if (action != PSACTOPEN)
  1588.     {   menumsg.action = action;
  1589.         menumsg.result = retcode;
  1590.         menumsg.errnum = errcode;
  1591.         PutMsg(menuport, (struct Message *) &menumsg);
  1592.     }
  1593.     WaitPort(mainport);
  1594.     GetMsg(mainport);
  1595.     retcode = menumsg.result;
  1596. }
  1597.  
  1598. /* The menu handler task */
  1599.  
  1600. static int pause = 1;
  1601.  
  1602. void __saveds menuproc(void)
  1603. {   struct Message *msg;
  1604.     char *title, *oldtitle, *savetitle;
  1605.     int height, i, j;
  1606.  
  1607.     title = titlestart;
  1608.     height = newintwindow.Height;
  1609.     msg = (struct Message *) &menumsg;
  1610.  
  1611.     /* Loop handling messages.  We access the initial message directly,
  1612.      * rather than getting it from the menu port, as we havn't created the
  1613.      * port yet */
  1614.  
  1615.     for (;;)
  1616.     {
  1617.         /* Message from main program */
  1618.  
  1619.         if ((struct PSmessage *) msg == &menumsg)
  1620.         {   switch (menumsg.action)
  1621.             {
  1622.                 /* Open the windows and initialise */
  1623.  
  1624.                 case PSACTOPEN:
  1625.                     menuport = CreatePort(NULL, 0);
  1626.                     if (menuport == NULL)
  1627.                     {   menumsg.result = 20;
  1628.                         goto end;
  1629.                     }
  1630.                     bitwindow->UserPort = menuport;
  1631.                     intwindow->UserPort = menuport;
  1632.                     ModifyIDCMP(bitwindow,
  1633.                             REFRESHWINDOW|ACTIVEWINDOW|GADGETUP);
  1634.                     ModifyIDCMP(intwindow,
  1635.                             REFRESHWINDOW|MENUPICK);
  1636.                     menu2->Flags |= MENUENABLED;
  1637.                     SetMenuStrip(intwindow, menu0);
  1638.                     SetWindowTitles(intwindow, NULL, (UBYTE *) title);
  1639.                     ReplyMsg(msg);
  1640.                     break;
  1641.  
  1642.                 /* Close the windows and tidy up */
  1643.  
  1644.                 case PSACTCLOSE:
  1645.                     ClearMenuStrip(intwindow);
  1646.                     ModifyIDCMP(bitwindow, CLOSEWINDOW);
  1647.                     ModifyIDCMP(intwindow, CLOSEWINDOW);
  1648.                     bitwindow->UserPort = NULL;
  1649.                     intwindow->UserPort = NULL;
  1650.                     for (;;)
  1651.                     {   msg = GetMsg(menuport);
  1652.                         if (msg == NULL) break;
  1653.                         ReplyMsg(msg);
  1654.                     }
  1655.                     DeletePort(menuport);
  1656.                     menuport = NULL;
  1657.                     goto end;
  1658.  
  1659.                 /* Flush the bitmap to its window */
  1660.  
  1661.                 case PSACTFLUSH:
  1662.                     i = menumsg.y1;
  1663.                     j = menumsg.y2;
  1664.                     if (i < winypos) i = winypos;
  1665.                     if (j < winypos) j = winypos;
  1666.                     if (i > winypos + winysize) i = winypos + winysize;
  1667.                     if (j > winypos + winysize) j = winypos + winysize;
  1668.                     if (j > i && argscreen)
  1669.                     {   BltBitMapRastPort(&bitmap, winxpos, i,
  1670.                                           bitwindow->RPort,
  1671.                                           winxbase, winybase + i - winypos,
  1672.                                           winxsize, j - i, 0xC0);
  1673.                     }
  1674.                     ReplyMsg(msg);
  1675.                     break;
  1676.  
  1677.                 /* Pause at the end of a page */
  1678.  
  1679.                 case PSACTPAUSE:
  1680.                     if (pause)
  1681.                     {   savetitle = title;
  1682.                         title = titlepaused;
  1683.                         SetWindowTitles(intwindow, NULL, (UBYTE *) title);
  1684.                         OnMenu(intwindow, 2 | SHIFTITEM(1));
  1685.                     }
  1686.                     else
  1687.                         ReplyMsg(msg);
  1688.                     break;
  1689.  
  1690.                 /* Get the next command */
  1691.  
  1692.                 case PSACTCOMMAND:
  1693.                     title = titlewait;
  1694.                     SetWindowTitles(intwindow, NULL, (UBYTE *) title);
  1695.                     OnMenu(intwindow, 0 | SHIFTITEM(NOITEM));
  1696.                     OnMenu(intwindow, 1 | SHIFTITEM(NOITEM));
  1697.                     break;
  1698.  
  1699.                 /* Get a quit or restart command */
  1700.  
  1701.                 case PSACTEXIT:
  1702.                     title = titlewait;
  1703.                     SetWindowTitles(intwindow, NULL, (UBYTE *) title);
  1704.                     OnMenu(intwindow, 0 | SHIFTITEM(NOITEM));
  1705.                     OffMenu(intwindow, 2 | SHIFTITEM(NOITEM));
  1706.                     break;
  1707.             }
  1708.         }
  1709.  
  1710.         /* Message from Intuition */
  1711.  
  1712.         else
  1713.         {   switch (((struct IntuiMessage *) msg)->Class)
  1714.             {
  1715.                 /* Make the interactive window the active one, but only if
  1716.                  * the scroll gadget knobs in the bitmapped window are not
  1717.                  * currently hit (so as not to prevent dragging them). (If
  1718.                  * someone is dragging them we will get a GADGETUP message
  1719.                  * when he lets go.) */
  1720.  
  1721.           /* As of 2/6/93, a special checkbox gadget is available
  1722.          which disables the changing of active focus to the
  1723.          interactive window; this removes an annoying conflict with
  1724.          sunmouse and autopoint commodities */
  1725.  
  1726.                 case ACTIVEWINDOW:
  1727.                     if (!(hscrollgadg.Flags & SELECTED) &&
  1728.                         !(vscrollgadg.Flags & SELECTED) &&
  1729.             !sunmouse_compat)
  1730.                         ActivateWindow(intwindow);
  1731.                     break;
  1732.  
  1733.                 /* Refresh a window */
  1734.  
  1735.                 case REFRESHWINDOW:
  1736.  
  1737.                     /* Refresh the bitmapped window */
  1738.  
  1739.                     if (((struct IntuiMessage *)msg)->IDCMPWindow ==
  1740.                                                                  bitwindow)
  1741.                     {   BeginRefresh(bitwindow);
  1742.                         if (argscreen)
  1743.                             BltBitMapRastPort(&bitmap, winxpos, winypos,
  1744.                                               bitwindow->RPort,
  1745.                                               winxbase, winybase,
  1746.                                               winxsize, winysize, 0xC0);
  1747.                         EndRefresh(bitwindow, TRUE);
  1748.                     }
  1749.  
  1750.                     /* We don't actually refresh the interactive window, but
  1751.                      * instead we use this event to tell us when it has
  1752.                      * changed size, so we can adjust the size and position
  1753.                      * of the bitmapped window to match.  (Despite what the
  1754.                      * manual says we seem to get the refresh message even
  1755.                      * when the window gets smaller */
  1756.  
  1757.                     else
  1758.                     {   i = intwindow->Height;
  1759.                         j = i - height;
  1760.                         height = i;
  1761.                         if      (j < 0)
  1762.                         {   MoveWindow(bitwindow, 0, j);
  1763.                             SizeWindow(bitwindow, 0, -j);
  1764.                         }
  1765.                         else if (j > 0)
  1766.                         {   SizeWindow(bitwindow, 0, -j);
  1767.                             MoveWindow(bitwindow, 0, j);
  1768.                         }
  1769.                         winypos += j;
  1770.                         if (winypos < 0) winypos = 0;
  1771.                         winysize -= j;
  1772.                         ModifyProp(&vscrollgadg, bitwindow, NULL,
  1773.                             AUTOKNOB|FREEVERT,
  1774.                             -1, (0xffff * winypos) /
  1775.                                     (parm.page.ysize - winysize),
  1776.                             -1, (0xffff * winysize) / parm.page.ysize);
  1777.  
  1778.             /* 2/6/93 -- minor bugfix.  Post V1.7 didn't
  1779.                properly refresh the bitmap window when the
  1780.                interactive window was resized. */
  1781.             if (argscreen)
  1782.               BltBitMapRastPort(&bitmap, winxpos, winypos,
  1783.                         bitwindow->RPort,
  1784.                         winxbase, winybase,
  1785.                         winxsize, winysize, 0xC0);
  1786.               }
  1787.  
  1788.                     break;
  1789.  
  1790.                 /* Scroll the bitmapped window.  Make sure we can scroll to
  1791.                  * the edges of the page, even after rounding erors */
  1792.  
  1793.                 case GADGETUP:
  1794.                     ActivateWindow(intwindow);
  1795.                     if      (((struct IntuiMessage *) msg)->IAddress ==
  1796.                                     (APTR) &hscrollgadg)
  1797.                     {   i = (parm.page.xsize - winxsize);
  1798.                         j = (i * hscrollinfo.HorizPot) / 65535;
  1799.                         if (j < i / 30) j = 0;
  1800.                         if (i - j < i / 30) j = i;
  1801.                         winxpos = j;
  1802.                     }
  1803.                     else if (((struct IntuiMessage *) msg)->IAddress ==
  1804.                                     (APTR) &vscrollgadg)
  1805.                     {   i = (parm.page.ysize - winysize);
  1806.                         j = (i * vscrollinfo.VertPot) / 65535;
  1807.                         if (j < i / 30) j = 0;
  1808.                         if (i - j < i / 30) j = i;
  1809.                         winypos = j;
  1810.                     }
  1811.                     if (argscreen)
  1812.                         BltBitMapRastPort(&bitmap, winxpos, winypos,
  1813.                                           bitwindow->RPort,
  1814.                                           winxbase, winybase,
  1815.                                           winxsize, winysize, 0xC0);
  1816.                     break;
  1817.  
  1818.                 /* Menu selection.  We don't implement extended selection
  1819.                  * to avoid real time problems, and it wouldn't be useful
  1820.                  * for our range of choices anyway */
  1821.  
  1822.                 case MENUPICK:
  1823.                     i = ((struct IntuiMessage *) msg)->Code;
  1824.                     j = ITEMNUM(i);
  1825.                     i = MENUNUM(i);
  1826.                     oldtitle = title;
  1827.                     if      (i == 0)     /* Project */
  1828.                     {   if      (j == 0) /*   Restart */
  1829.                             menumsg.command = PSCOMRESTART;
  1830.                         else if (j == 1) /*   Quit */
  1831.                             menumsg.command = PSCOMQUIT;
  1832.                     }
  1833.                     else if (i == 1)     /* File */
  1834.                     {   title = titlerunning;
  1835.                         if      (j == 0) /*   Load font */
  1836.                             menumsg.command = PSCOMFILEF;
  1837.                         else if (j == 1) /*   Load file */
  1838.                             menumsg.command = PSCOMFILEL;
  1839.                         else if (j == 2) /*   Run file */
  1840.                             menumsg.command = PSCOMFILER;
  1841.                         else if (j == 3) /*   Interactive */
  1842.                         {   menumsg.command = PSCOMINTER;
  1843.                             title = titleinter;
  1844.                         }
  1845.                     }
  1846.                     else if (i == 2)     /* Control */
  1847.                     {   if      (j == 0) /*   Pause every page */
  1848.                         {   pause = !pause;
  1849.                             if (pause)
  1850.                                 menu2->FirstItem->Flags |=  CHECKED;
  1851.                             else
  1852.                                 menu2->FirstItem->Flags &= ~CHECKED;
  1853.                             break;
  1854.                         }
  1855.                         else if (j == 1) /*   Continue after pause */
  1856.                         {   menumsg.command = 0;
  1857.                             title = savetitle;
  1858.                             OffMenu(intwindow, 2 | SHIFTITEM(1));
  1859.                         }
  1860.                         else if (j == 2) /*   Interrupt */
  1861.                         {   PSsignalint(arec, 1);
  1862.                             break;
  1863.                         }
  1864.                         else if (j == 3) /*   Kill */
  1865.                         {   PSsignalint(arec, 2);
  1866.                             break;
  1867.                         }
  1868.                     }
  1869.                     else                 /* NULL */
  1870.                         break;
  1871.                     OffMenu(intwindow, 0 | SHIFTITEM(NOITEM));
  1872.                     OffMenu(intwindow, 1 | SHIFTITEM(NOITEM));
  1873.                     if (title != oldtitle)
  1874.                         SetWindowTitles(intwindow, NULL, (UBYTE *) title);
  1875.                     menumsg.length = -1;
  1876.                     menumsg.string = NULL;
  1877.                     ReplyMsg((struct Message *) &menumsg);
  1878.                     break;
  1879.             }
  1880.             ReplyMsg(msg);
  1881.         }
  1882.  
  1883.         /* Get next message */
  1884.  
  1885.         for (;;)
  1886.         {   msg = GetMsg(menuport);
  1887.             if (msg) break;
  1888.             WaitPort(menuport);
  1889.         }
  1890.     }
  1891.  
  1892.     /* Open failure or close.  Reply remove our task */
  1893.  
  1894. end:
  1895.     Forbid();
  1896.     ReplyMsg((struct Message *) &menumsg);
  1897.     menutask = NULL;
  1898.     RemTask(menutask);
  1899. }
  1900.  
  1901. /* Signal an interrupt */
  1902.  
  1903. void __saveds sigint()
  1904. {   PSsignalint(arec, 1);
  1905. }
  1906.  
  1907. /* Signal a floating point error */
  1908.  
  1909. void __saveds sigfpe()
  1910. {   PSsignalfpe(arec);
  1911. }
  1912.  
  1913. /* Call an external function (dummy) */
  1914.  
  1915. # ifdef STATICLINK
  1916. int callextfunc(APTR func, APTR aptr, int parms)
  1917. {   return 0;
  1918. }
  1919. # endif
  1920.  
  1921. /* Flush the page to the screen */
  1922.  
  1923. # ifdef STATICLINK
  1924. void flushpage(int y1, int y2)
  1925. # else
  1926. void __saveds __asm flushpage(register __d0 int y1, register __d1 int y2)
  1927. # endif
  1928. {   if (argscreen)
  1929.     {   menumsg.y1 = y1;
  1930.         menumsg.y2 = y2;
  1931.         sendmenu(PSACTFLUSH);
  1932.     }
  1933. }
  1934.  
  1935. /* Copy the page to the output */
  1936.  
  1937. # ifdef STATICLINK
  1938. void copypage(int num)
  1939. # else
  1940. void __saveds __asm copypage(register __d0 int num)
  1941. # endif
  1942. {   ioerror = 0;
  1943.     if (argprint)
  1944.         while (num--) printpage();
  1945.     if (argiff)
  1946.         iffpage();
  1947.     if (argscreen)
  1948.         sendmenu(PSACTPAUSE);
  1949.     if (ioerror) PSerror(arec, ioerror);
  1950. }
  1951.  
  1952. /* Print the page */
  1953.  
  1954. void printpage()
  1955. {   ULONG sig;
  1956.     UWORD prflags;
  1957.  
  1958.     /* Disable break exceptions so we can wait on the signal instead */
  1959.  
  1960.     SetExcept(0, SIGBREAKF_CTRL_C);
  1961.     breakset = 0;
  1962.  
  1963.     /* First check the printer is ready */
  1964.  
  1965.     prreq.io_Command = PRD_QUERY;
  1966.     ((struct IOStdReq *) &prreq)->io_Data = (APTR) prstatus;
  1967.     if (DoIO((struct IORequest *) &prreq))
  1968.     {   ioerror = errioerror;
  1969.         return;
  1970.     }
  1971.     if (((struct IOStdReq *) &prreq)->io_Actual == 1 && prstatus[0] & 3 != 0)
  1972.         FPrintf(argint ? confh : errfh,
  1973.                 "post: printer not ready (CTRL/C to abort)\n");
  1974.  
  1975.     /* Now dump the page */
  1976.  
  1977.     prrast.BitMap = &bitmap;
  1978.     prreq.io_Command = PRD_DUMPRPORT;
  1979.     prreq.io_RastPort = &prrast;
  1980.     prreq.io_ColorMap = (struct ColorMap *) &colormap;
  1981.     prreq.io_Modes = 0;
  1982.     prreq.io_SrcX = 0;
  1983.     prreq.io_SrcY = 0;
  1984.     prreq.io_SrcWidth = parm.page.xsize;
  1985.     prreq.io_SrcHeight = parm.page.ysize;
  1986.     prreq.io_Special = (SPECIAL_DENSITY1 * prden) | SPECIAL_TRUSTME;
  1987.     if (parm.page.ybase + parm.page.ysize >= parm.page.yheight)
  1988.         prreq.io_SrcHeight = parm.page.yheight - parm.page.ybase;
  1989.     else
  1990.         prreq.io_Special |= SPECIAL_NOFORMFEED;
  1991.     if (prextdata->ped_MaxXDots != 0)
  1992.         if (prreq.io_SrcWidth > prextdata->ped_MaxXDots)
  1993.             prreq.io_SrcWidth = prextdata->ped_MaxXDots;
  1994.     if (prextdata->ped_MaxYDots != 0)
  1995.         if (prreq.io_SrcHeight > prextdata->ped_MaxYDots)
  1996.             prreq.io_SrcHeight = prextdata->ped_MaxYDots;
  1997.     prreq.io_DestCols = prreq.io_SrcWidth;
  1998.     prreq.io_DestRows = prreq.io_SrcHeight;
  1999.     prflags = prprefs->PrintFlags;
  2000.     prprefs->PrintFlags = prflags & ~DIMENSIONS_MASK | IGNORE_DIMENSIONS;
  2001.  
  2002.     /* We use asynchronous IO so we can abort it with a CTRL/C */
  2003.  
  2004.     SendIO((struct IORequest *) &prreq);
  2005.  
  2006.     for (;;)
  2007.     {   sig = Wait(prsig | SIGBREAKF_CTRL_C);
  2008.         if (sig & SIGBREAKF_CTRL_C)
  2009.         {   AbortIO((struct IORequest *) &prreq);
  2010.             WaitIO((struct IORequest *) &prreq);
  2011.             ioerror = errioerror;
  2012.             break;
  2013.         }
  2014.         if (GetMsg(prport))
  2015.             break;
  2016.     }
  2017.     if (prreq.io_Error != 0) ioerror = errioerror;
  2018.  
  2019.     /* Restore break exceptions */
  2020.  
  2021.     SetExcept(~0, SIGBREAKF_CTRL_C);
  2022.     breakset = 1;
  2023.  
  2024.     prprefs->PrintFlags = prflags;
  2025. }
  2026.  
  2027. /* IFF ILBM routines */
  2028.  
  2029. static int iffseq = 0;
  2030.  
  2031. static int ifferr;
  2032.  
  2033. static FILE *ifffptr;
  2034.  
  2035. /* Put a byte */
  2036.  
  2037. static void iffputb(int b)
  2038. {   if (ifferr) return;
  2039.     if (putc((int) b, ifffptr) == EOF)
  2040.     {   ifferr = 1;
  2041.         return;
  2042.     }
  2043. }
  2044.  
  2045. /* Put a word */
  2046.  
  2047. static void iffputw(int w)
  2048. {   iffputb(w>>8);
  2049.     iffputb(w);
  2050. }
  2051.  
  2052. /* Put a long */
  2053.  
  2054. static void iffputl(int l)
  2055. {   iffputb(l>>24);
  2056.     iffputb(l>>16);
  2057.     iffputb(l>>8);
  2058.     iffputb(l);
  2059. }
  2060.  
  2061. /* Put a string */
  2062.  
  2063. static void iffputs(char *str)
  2064. {   while (*str) iffputb(*str++);
  2065. }
  2066.  
  2067. /* Pack a bitmap row */
  2068.  
  2069. static void iffpack(char *buf, int len)
  2070. {   int b, c, l;
  2071.     if (ifferr) return;
  2072.     l = 0;
  2073.     while (len--)
  2074.     {   b = *buf++;                  /* Pick up a byte */
  2075.         c = 1;
  2076.         while (len && *buf == b && c < 128)
  2077.         {   c++;
  2078.             buf++;
  2079.             len--;                   /* See if it begins a run */
  2080.         }
  2081.         if (c == 2 &&                /* If a two byte run */
  2082.             l > 0 &&                 /*    and preceeded by literals */
  2083.             l <= 125 &&              /*    and not more than 125 of them */
  2084.             (len <= 2 ||             /*    and no more than 2 bytes left */
  2085.              *buf != *(buf + 1)))    /*        or not followed by a run */
  2086.         {   c = 1;                   /* Then make it a literal */
  2087.             buf--;
  2088.             len++;
  2089.         }
  2090.         if (c == 1)                  /* If not a run */
  2091.         {   l++;                     /* Then it must be a literal */
  2092.             c = 0;
  2093.         }
  2094.         if (l > 0 &&                 /* If we have some literals */
  2095.             (c > 1 ||                /*    and beginning a run */
  2096.              l == 127 ||             /*    or reached 127 */
  2097.              len == 0))              /*    or no more bytes left */
  2098.         {   if (putc(l - 1, ifffptr) == EOF)
  2099.             {   ifferr = 1;
  2100.                 return;
  2101.             }
  2102.             while (l)              /* Then write out  the literals */
  2103.             {   if (putc(*(buf - c - l), ifffptr) == EOF)
  2104.                 {   ifferr = 1;
  2105.                     return;
  2106.                 }
  2107.                 l--;
  2108.             }
  2109.         }
  2110.         if (c > 1)                   /* If we have a run, write it */
  2111.         {   if (putc(1 - c, ifffptr) == EOF)
  2112.             {   ifferr = 1;
  2113.                 return;
  2114.             }
  2115.             if (putc(b, ifffptr) == EOF)
  2116.             {   ifferr = 1;
  2117.                 return;
  2118.             }
  2119.         }
  2120.     }
  2121. }
  2122.  
  2123. /* Determine the current address */
  2124.  
  2125. static long ifftell(void)
  2126. {   long addr;
  2127.     if (ifferr) return 0;
  2128.     if ((addr = ftell(ifffptr)) == -1)
  2129.     {   ifferr = 1;
  2130.         return 0;
  2131.     }
  2132.     return addr;
  2133. }
  2134.  
  2135. /* Fix up the length of a chunk */
  2136.  
  2137. static void ifffixup(long addr)
  2138. {   long size;
  2139.     if (ifferr) return;
  2140.     if ((size = ftell(ifffptr)) == -1)
  2141.     {   ifferr = 1;
  2142.         return;
  2143.     }
  2144.     if (size & 1) iffputb(0);
  2145.     size = size - addr - 8;
  2146.     if (fseek(ifffptr, addr + 4, 0) != 0)
  2147.     {   ifferr = 1;
  2148.         return;
  2149.     }
  2150.     iffputl(size);
  2151.     if (fseek(ifffptr, 0, 2) != 0)
  2152.     {   ifferr = 1;
  2153.         return;
  2154.     }
  2155. }
  2156.  
  2157. /* Write the page to the iff output file */
  2158.  
  2159. void iffpage(void)
  2160. {   long addr1, addr2;
  2161.     int xa, ya;
  2162.     int i, j, k, ch;
  2163.     UWORD w;
  2164.     int fslen;
  2165.     char fname[110], fsnum[10];
  2166.  
  2167.     /* Compute the aspect ratio.  Make sure the values fit into a byte */
  2168.  
  2169.     xa = parm.page.yden;
  2170.     ya = parm.page.xden;
  2171.     i = igcd(xa, ya);
  2172.     xa /= i;
  2173.     ya /= i;
  2174.     while (xa > 255 && ya > 255)
  2175.     {   xa /= 2;
  2176.         ya /= 2;
  2177.     }
  2178.  
  2179.     /* Construct the file name.  Copy it, replacing "*" by the sequence
  2180.      * number.  The scan it backwards replacing "?" by digits */
  2181.  
  2182.     iffseq++;
  2183.     fslen = 0;
  2184.     i = iffseq;
  2185.     while (i)
  2186.     {   fsnum[fslen++] = i % 10 + '0';
  2187.         i /= 10;
  2188.     }
  2189.     i = j = 0;
  2190.     for (;;)
  2191.     {   if (j > 100)
  2192.         {   ioerror = errioerror;
  2193.             return;
  2194.         }
  2195.         ch = argifn[i++];
  2196.         if (ch == '*')
  2197.         {   k = fslen;
  2198.             while (k--) fname[j++] = fsnum[k];
  2199.         }
  2200.         else
  2201.            fname[j++] = ch;
  2202.         if (ch == 0) break;
  2203.     }
  2204.     k = 0;
  2205.     while (--j)
  2206.     {   if (fname[j] == '?')
  2207.             fname[j] = (k < fslen) ? fsnum[k++] : '0';
  2208.     }
  2209.  
  2210.     /* Open the file, write a FORM ILBM, and close it again */
  2211.  
  2212.     ifferr = 0;
  2213.     ifffptr = fopen(fname, "wb");
  2214.     if (ifffptr == NULL) ifferr = 1;
  2215.  
  2216.     addr1 = ifftell();
  2217.     iffputs("FORM");          /* FORM ILBM */
  2218.     iffputl(0);
  2219.     iffputs("ILBM");
  2220.  
  2221.     iffputs("BMHD");          /* BMHD */
  2222.     iffputl(20);
  2223.     iffputw(parm.page.xsize); /* Width */
  2224.     iffputw(parm.page.ysize); /* Height */
  2225.     iffputw(0);               /* X position */
  2226.     iffputw(0);               /* Y position */
  2227.     iffputb(parm.page.depth); /* Number of bit planes */
  2228.     iffputb(0);               /* Masking:     None */
  2229.     iffputb(1);               /* Compression: ByteRun */
  2230.     iffputb(0);               /* Pad1 */
  2231.     iffputw(0);               /* Transparent colour */
  2232.     iffputb(xa);              /* X aspect */
  2233.     iffputb(ya);              /* Y aspect */
  2234.     iffputw(parm.page.xsize); /* Source width */
  2235.     iffputw(parm.page.ysize); /* Source height */
  2236.  
  2237.     addr2 = ifftell();
  2238.     iffputs("CMAP");          /* CMAP */
  2239.     iffputl(0);
  2240.     for (i = 0; i < colormap.Count; i++)
  2241.     {   w = ((UWORD *) colormap.ColorTable)[i];
  2242.         iffputb(((w >> 8) & 15) << 4);
  2243.         iffputb(((w >> 4) & 15) << 4);
  2244.         iffputb(( w       & 15) << 4);
  2245.     }
  2246.     ifffixup(addr2);
  2247.  
  2248.     if (argscreen)
  2249.     {   iffputs("CAMG");      /* CAMG */
  2250.         iffputl(4);
  2251.         iffputl(newscreen.ViewModes);
  2252.     }
  2253.  
  2254.     addr2 = ifftell();
  2255.     iffputs("BODY");          /* BODY */
  2256.     iffputl(0);
  2257.     for (j = 0; j < bitmap.Rows; j++)
  2258.         for (i = 0; i < bitmap.Depth; i++)
  2259.             iffpack((char *) bitmap.Planes[i] + j * bitmap.BytesPerRow,
  2260.                     bitmap.BytesPerRow);
  2261.     ifffixup(addr2);
  2262.  
  2263.     ifffixup(addr1);
  2264.  
  2265.     if (fclose(ifffptr) == EOF)
  2266.         ifferr = 1;
  2267.     if (ifferr) ioerror = errioerror;
  2268. }
  2269.  
  2270. /* Find the greatest common divisor of two positive integers.  If one is
  2271.  * zero the result is the other */
  2272.  
  2273. int igcd(int n, int m)
  2274. {   unsigned int n1, m1, r;
  2275.     if      (n > m)
  2276.     {   n1 = n;
  2277.         m1 = m;
  2278.     }
  2279.     else if (m > n)
  2280.     {   n1 = m;
  2281.         m1 = n;
  2282.     }
  2283.     else
  2284.         return n;
  2285.     while (m1 != 0)
  2286.     {   r = n1 % m1;
  2287.         n1 = m1;
  2288.         m1 = r;
  2289.     }
  2290.     return (int) n1;
  2291. }
  2292.  
  2293. /* a total HACK */
  2294. void TackOn(char *target, char *string1, char *string2)
  2295. {
  2296.   strcpy(target, string1);
  2297.   /* string1 is a directory, string2 is a file name; what we want to do
  2298.      is append the filename to the directory name.  If the directory
  2299.      name is a null-string or if it ends in a colon, we don't stick
  2300.      any extra characters in there, otherwise we stick a / between the
  2301.      directory path and the filename */
  2302.   if (strlen(string1) > 0 && string1[strlen(string1) - 1] != ':') {
  2303.     strcat(target, "/");
  2304.   }
  2305.   strcat(target, string2);
  2306. }
  2307.  
  2308. /* End of file "post.c" */
  2309.